<?php
if(!defined('METAL_LIBRARY_XML_XML_WRITER_CLASS'))
{
	define('METAL_LIBRARY_XML_XML_WRITER_CLASS',1);

/*
 *
 * Copyright � (C) Manuel Lemos 2001-2002
 *
 * @(#) $Id: xmlwriterclass.class,v 1.35 2007/09/17 21:00:20 mlemos Exp $
 *
 */

class BaseXmlWriter
{
	/*
	 * Protected variables
	 *
	 */
	var $nodes=array();
	
	/*
	 * Package variables
	 *
	 */
	var $structure=array();
	
	/*
	 * Public variables
	 *
	 */
	var $stylesheet='';
	var $stylesheettype='text/xsl';
	var $dtdtype='';
	var $dtddefinition='';
	var $dtdurl='';
	var $outputencoding='utf-8';
	//var $inputencoding='iso-8859-1';
	var $inputencoding='utf-8';
	var $linebreak="\n";
	var $indenttext=' ';
	var $generatedcomment='Generated by: http://www.phpclasses.org/xmlwriter $Revision: 1.35 $';
	var $error='';
	
	
	/*
	 * Protected functions
	 *
	 */
	Function encodedata($data,&$encodeddata)
	{
		$inputencoding=strtolower($this->inputencoding);
		if(!strcmp($inputencoding,strtolower($this->outputencoding)))
			$encodeddata=$this->escapedata($data);
		else
		{
			switch(strtolower($this->outputencoding))
			{
				case 'utf-8':
					if(!strcmp($inputencoding,'iso-8859-1'))
					{
						$encoded_data=utf8_encode($this->escapedata($data));
						$encodeddata=$encoded_data;
					}
					else
					{
						$this->error=('can not encode iso-8859-1 data in '.$this->outputencoding);
						return 0;
					}
					break;
				case 'iso-8859-1':
					if(!strcmp($inputencoding,'utf-8'))
					{
						$decoded=utf8_decode($data);
						$encodeddata=$this->escapedata($decoded);
					}
					else
					{
						$this->error=('can not encode utf-8 data in '.$this->outputencoding);
						return 0;
					}
					break;
				default:
					$this->error=('can not encode data in '.$this->inputencoding);
					return 0;
			}
		}
		return 1;
	}
	
	Function writetag(&$output,$path,$indent)
	{
		$tag=$this->structure[$path]['Tag'];
		$output.=('<'.$tag);
		$attributecount=count($this->structure[$path]['Attributes']);
		if($attributecount>0)
		{
			$attributes=&$this->structure[$path]['Attributes'];
			Reset($attributes);
			$end=(GetType($key=Key($attributes))!='string');
			for(;!$end;)
			{
				$output.=(' '.$key.'="'.$attributes[$key].'"');
				Next($attributes);
				$end=(GetType($key=Key($attributes))!='string');
			}
		}
		$elements=$this->structure[$path]['Elements'];
		if($elements>0)
		{
			$output.='>';
			$doindent=$this->structure[$path]['Indent'];
			$elementindent=(($doindent) ? $this->linebreak.$indent.$this->indenttext : '');
			$element=0;
			for(;$element<$elements;)
			{
				$elementpath=($path.','.strval($element));
				$output.=$elementindent;
				if(IsSet($this->nodes[$elementpath]))
				{
					if(!($this->writetag($output,$elementpath,$indent.$this->indenttext)))
						return 0;
				}
				else
					$output.=$this->structure[$elementpath];
				$element++;
			}
			$output.=((($doindent) ? $this->linebreak.$indent : '').'</'.$tag.'>');
		}
		else
			$output.='/>';
		return 1;
	}
	
	/*
	 * Package functions
	 *
	 */
	Function escapedata($data)
	{
		$position=0;
		$length=strlen($data);
		$escapeddata='';
		for(;$position<$length;)
		{
			$character=substr($data,$position,1);
			$code=Ord($character);
			switch($code)
			{
				case 34:
					$character='&quot;';
					break;
				case 38:
					$character='&amp;';
					break;
				case 39:
					$character='&apos;';
					break;
				case 60:
					$character='&lt;';
					break;
				case 62:
					$character='&gt;';
					break;
				default:
					if($code<32)
						$character=('&#'.strval($code).';');
					break;
			}
			$escapeddata.=$character;
			$position++;
		}
		return $escapeddata;
	}
	
	/*
	 * Public functions
	 *
	 */
	Function write(&$output)
	{
		if(strcmp($this->error,''))
			return 0;
		if(!(IsSet($this->structure['0'])))
		{
			$this->error='XML document structure is empty';
			return 0;
		}
		$output=('<?xml version="1.0" encoding="'.$this->outputencoding.'"?>'.$this->linebreak);
		if(strcmp($this->dtdtype,''))
		{
			$output.=('<!DOCTYPE '.$this->structure['0']['Tag'].' ');
			switch($this->dtdtype)
			{
				case 'INTERNAL':
					if(!strcmp($this->dtddefinition,''))
					{
						$this->error='it was not specified a valid internal DTD definition';
						return 0;
					}
					$output.=('['.$this->linebreak.$this->dtddefinition.$this->linebreak.']');
					break;
				case 'SYSTEM':
					if(!strcmp($this->dtdurl,''))
					{
						$this->error='it was not specified a valid system DTD url';
						return 0;
					}
					$output.='SYSTEM';
					if(strcmp($this->dtddefinition,''))
						$output.=(' "'.$this->dtddefinition.'"');
					$output.=(' "'.$this->dtdurl.'"');
					break;
				case 'PUBLIC':
					if(!strcmp($this->dtddefinition,''))
					{
						$this->error='it was not specified a valid public DTD definition';
						return 0;
					}
					$output.=('PUBLIC "'.$this->dtddefinition.'"');
					if(strcmp($this->dtdurl,''))
						$output.=(' "'.$this->dtdurl.'"');
					break;
				default:
					$this->error='it was not specified a valid DTD type';
					return 0;
			}
			$output.=('>'.$this->linebreak);
		}
		if(strcmp($this->stylesheet,''))
		{
			if(!strcmp($this->stylesheettype,''))
			{
				$this->error='it was not specified a valid stylesheet type';
				return 0;
			}
			$output.=('<?xml-stylesheet type="'.$this->stylesheettype.'" href="'.$this->stylesheet.'"?>'.$this->linebreak);
		}
		if(strcmp($this->generatedcomment,''))
			$output.=('<!-- '.$this->generatedcomment.' -->'.$this->linebreak);
		return $this->writetag($output,'0','');
	}
	
	Function addtag($tag,&$attributes,$parent,&$path,$indent)
	{
		if(strcmp($this->error,''))
			return 0;
		$path=((!strcmp($parent,'')) ? '0' : ($parent.','.strval($this->structure[$parent]['Elements'])));
		if(IsSet($this->structure[$path]))
		{
			$this->error=('tag with path '.$path.' is already defined');
			return 0;
		}
		$encodedattributes=array();
		Reset($attributes);
		$end=(GetType($attribute_name=Key($attributes))!='string');
		for(;!$end;)
		{
			$encodedattributes[$attribute_name]='';
			if(!($this->encodedata($attributes[$attribute_name],$encoded_data)))
				return 0;
			$encodedattributes[$attribute_name]=$encoded_data;
			Next($attributes);
			$end=(GetType($attribute_name=Key($attributes))!='string');
		}
		$this->structure[$path]=array(
			'Tag'=>$tag,
			'Attributes'=>$encodedattributes,
			'Elements'=>0,
			'Indent'=>$indent
		);
		$this->nodes[$path]=1;
		if(strcmp($parent,''))
			$this->structure[$parent]['Elements']=($this->structure[$parent]['Elements']+1);
		return 1;
	}
	
	Function adddata($data,$parent,&$path)
	{
		if(strcmp($this->error,''))
			return 0;
		if(!(IsSet($this->structure[$parent])))
		{
			$this->error=('the parent tag path'.$path.'is not defined');
			return 0;
		}
		if(!strcmp($data,''))
			return 1;
		$path=($parent.','.strval($this->structure[$parent]['Elements']));
		if(!($this->encodedata($data,$encoded_data)))
			return 0;
		$this->structure[$path]=$encoded_data;
		$this->structure[$parent]['Elements']=($this->structure[$parent]['Elements']+1);
		return 1;
	}
	
	Function adddatatag($tag,&$attributes,$data,$parent,&$path)
	{
		return $this->addtag($tag,$attributes,$parent,$path,0) && $this->adddata($data,$path,$datapath);
	}
};

}
?>